/**
 * \file    SBMLValidator.java
 * \brief   Validates an SBML document using the SBML.org Online Validator
 * \author  Ben Bornstein <sbml-team@caltech.edu>
 *
 * $Id: SBMLValidator.java,v 1.1 2006/03/21 21:07:50 beshapiro Exp $
 * $Source: /cvsroot/sbml/mathsbml/SBMLValidator.java,v $
 *
 * Copyright 2006 California Institute of Technology and
 * Japan Science and Technology Corporation.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 2.1 of the License, or
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  The software and
 * documentation provided hereunder is on an "as is" basis, and the
 * California Institute of Technology and Japan Science and Technology
 * Corporation have no obligations to provide maintenance, support,
 * updates, enhancements or modifications.  In no event shall the
 * California Institute of Technology or the Japan Science and Technology
 * Corporation be liable to any party for direct, indirect, special,
 * incidental or consequential damages, including lost profits, arising
 * out of the use of this software and its documentation, even if the
 * California Institute of Technology and/or Japan Science and Technology
 * Corporation have been advised of the possibility of such damage.  See
 * the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 */


import java.net.URL;
import java.net.URLConnection;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.IOException;

import java.util.Random;


/**
 * Performs a Multipart HTTP post to the given URL.  A post operation
 * is started with the creation of a MultipartPost object.  Post
 * parameters are sent with writeParameter() and may be eithier
 * strings or the contents of an XML file.  A post is finished by
 * calling done() which returns an InputStream for reading the servers
 * response.
 *
 * NOTE: This class is meant to communicate with the SBML.org online
 * validator.  As such, it assumes uploaded files are XML and always
 * sends a Content-Type: text/xml.
 */
class MultipartPost
{
  public MultipartPost (String url) throws IOException
  {
    Random random = new Random();

    connection  = ( new URL(url) ).openConnection();
    boundary    = "<<" + Long.toString(random.nextLong(), 30);
    String type = "multipart/form-data; boundary=" + boundary;

    connection.setDoOutput(true);
    connection.setRequestProperty("Content-Type", type);

    stream = connection.getOutputStream();
  }

  public InputStream done () throws IOException
  {
    writeln("--" + boundary + "--");
    writeln();

    stream.close();

    return connection.getInputStream();
  }

  public void writeParameter (String name, String value) throws IOException
  {
    writeln("--" + boundary);
    writeln("Content-Disposition: form-data; name=\"" + name + "\"");
    writeln();
    writeln(value);
  }

  public void writeParameter (String name, File file) throws IOException
  {
    String prefix = "Content-Disposition: form-data; name=\"file\"; filename=";

    writeln("--" + boundary);
    writeln(prefix + '"' + file.getName() + '"');
    writeln("Content-Type: text/xml");
    writeln();

    InputStream source = new FileInputStream(file);
    copy(source, stream);

    stream.flush();
    source.close();
  }

  void copy (InputStream source, OutputStream destination) throws IOException
  {
    byte[] buffer = new byte[8192];
    int    nbytes = 0;

    while ((nbytes = source.read(buffer, 0, buffer.length)) >= 0)
    {
      destination.write(buffer, 0, nbytes);
    }
  }

  void writeln (String s) throws IOException
  {
    write(s);
    writeln();
  }

  void writeln () throws IOException
  {
    write('\r');
    write('\n');
  }

  void write (char c) throws IOException
  {
    stream.write(c);
  }

  void write (String s) throws IOException
  {
    stream.write(s.getBytes());
  }


  URLConnection connection;
  OutputStream  stream;
  String        boundary;
}


/**
 * SBMLValidator is simply a container for the static method
 * validateSBML(filename, parameters).
 */
public class SBMLValidator
{
  public SBMLValidator () { }


  /**
   * Validates the given SBML filename (or http:// URL) by calling the
   * SBML.org online validator.
   *
   * @return validation results as an XML string.
   */
  public String validateSBML (String filename)
  {
    return validateSBML(filename, "xml");
  }


  /**
   * Validates the given SBML filename (or http:// URL) by calling the
   * SBML.org online validator. The results are returned as an string
   * whose format may be controlled by setting output to one of:
   * "xml", "xhtml", "json", "text".
   *
   * @return validation results as a string.
   */
  public String validateSBML (String filename, String output)
  {
    String result;

    try
    {
      MultipartPost post = new MultipartPost("http://sbml.org/validator/");

      if (filename.startsWith("http://"))
      {
        post.writeParameter("url", filename);
      }
      else
      {
        post.writeParameter("file", new File(filename));
      }

      post.writeParameter("output", output);

      result = createString( post.done() );
    }
    catch (IOException e)
    {
      result = e.getMessage();
    }

    return result;
  }


  String createString (InputStream stream) throws IOException
  {
    BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
    String         line   = reader.readLine();
    StringBuffer   buffer = new StringBuffer();

    while (line != null)
    {
      buffer.append(line);
      buffer.append('\n');
      line = reader.readLine();
    }

    return buffer.toString();
  }


  static void usage ()
  {
    String usage =
      "usage: java SBMLValidator filename.xml [output-format]\n" +
      "usage: java SBMLValidator http://...   [output-format]\n" +
      "\n" +
      "Validates the SBML document given by filename.xml or located at\n" +
      "the http:// URL.  Output-format is optional and may be one of:\n"  +
      "xml, xhtml, json, text (default: xml)";

    System.out.println(usage);
    System.exit(1);
  }


  public static void main (String[] args)
  {
    if (args.length != 1 && args.length != 2)
    {
      usage();
    }

    String        filename  = args[0];
    String        output    = (args.length == 2) ? args[1] : "xml";
    SBMLValidator validator = new SBMLValidator();

    System.out.println( validator.validateSBML(filename, output) );
  }
}
